#pragma once

#include <winsock2.h>
#include <windows.h>

namespace WTB{

	template <typename T> 
	class CAtomic
	{
	private:
		volatile T m_tValue;
	public:

		CAtomic();
		CAtomic(const T _tValue);

		/*
		* Get the current value of m_tValue
		*
		*/
		T GetValue() const;

		/*
		* Get the specified bit of m_tValue
		*
		*@parm in _lOffset   The bit position to be geted.
		*
		*@return  unsigned char: (0 or 1) the value of the specified bit of m_tValue
		*/
		unsigned char GetBit(const long _lOffset) const;

		bool operator<(const T _tValue) const;

		bool operator<=(const T _tValue) const;

		bool operator==(const T _tValue) const;

		bool operator!=(const T _tValue) const;

		bool operator>=(const T _tValue) const;

		bool operator>(const T _tValue) const;

		/*
		* Increments the value of m_tValue as an atomic operation.
		* Then returns the initial(old) value of m_tValue
		*
		*@return  T: the initial(old) value of m_tValue
		*/
		T operator ++(int);

		/*
		*  Decrements the value of m_tValue as an atomic operation.
		* Then returns the initial(old) value of m_tValue
		*
		*@return  T: the initial(old) value of m_tValue
		*/
		T operator --(int);

		/*
		* Increments the value of m_tValue as an atomic operation.
		* Then returns the resulting value of m_tValue
		*
		*@return  T: the resulting value of m_tValue
		*/
		T operator ++();

		/*
		* Decrements the value of m_tValue as an atomic operation.
		* Then returns the resulting value of m_tValue
		*
		*@return  T: the resulting value of m_tValue
		*/
		T operator --();

		/*
		* Sets m_tValue to the specified value as an atomic operation.
		*
		*@parm in _tValue   the specified value 
		*
		*@return  void
		*/
		void operator = (const T _tValue);

		/*
		* Performs an atomic addition to m_tValue.
		* Then returns the initial(old) value of m_tValue
		*
		*@parm in _tValue   the value to be added to  m_tValue
		*
		*@return  T: the initial(old) value of m_tValue
		*/
		T AtomicAdd(const T _tValue);


		/*
		* Sets m_tValue to the specified value as an atomic operation.
		* Then function returns the initial value of m_tValue
		*
		*@parm in _tValue   the specified value 
		*
		*@return  T: the initial value of m_tValue
		*/
		T AtomicExchange(const T _tValue);

		/*
		* The function compares  m_tValue with the _tComparend value. 
		*If m_tValue is equal to the _tComparend value, the Exchange value is stored in 
		*the address specified by m_tValue. Otherwise, no operation is performed
		* Then function returns the initial(old) value of m_tValue
		*
		*@parm in _tSetValue   the value to be exchanged to  m_tValue
		*@parm in _tComparend  The value to compare to m_tValue
		*
		*@return  T: the initial(old) value of m_tValue
		*/
		T AtomicCompareExchange(const T _tSetValue,const T _tComparend);

		/*
		* Tests the specified bit of m_tValue and sets it to 1. The operation is atomic
		* Then function returns the initial(old) value of the specified bit of m_tValue
		*
		*@parm in _lOffset   The bit position to be tested.
		*
		*@return  unsigned char: (0 or 1) the initial(old) value of the specified bit of m_tValue
		*/
		unsigned char AtomicBitTestAndSet(const long _lOffset);

		/*
		* Tests the specified bit of m_tValue and sets it to 0. The operation is atomic
		* Then function returns the initial(old) value of the specified bit of m_tValue
		*
		*@parm in _lOffset   The bit position to be tested.
		*
		*@return  unsigned char: (0 or 1) the initial(old) value of the specified bit of m_tValue
		*/
		unsigned char AtomicBitTestAndReset(const long _lOffset);

		/*
		*Tests the specified bit of m_tValue and complements it. The operation is atomic.
		* Then function returns the initial(old) value of the specified bit of m_tValue
		*
		*@parm in _lOffset   The bit position to be tested.
		*
		*@return  unsigned char: (0 or 1) the initial(old) value of the specified bit of m_tValue
		*/
		unsigned char AtomicBitTestAndComplement(const long _lOffset);
	};

	template <typename T> 
	inline CAtomic<T>::CAtomic()
	{
		m_tValue = 0;
	}

	template <typename T>
	inline CAtomic<T>::CAtomic(const T _tValue)
	{
		m_tValue = _tValue;
	}

	template <typename T>
	inline T CAtomic<T>::GetValue() const
	{
		return m_tValue;
	}

	template <typename T>
	unsigned char CAtomic<T>::GetBit(const long _lOffset) const
	{
		return m_tValue & (1L<<_lOffset) ? 1 : 0;
	}

	template <typename T>
	inline bool CAtomic<T>::operator<(const T _tValue) const
	{
		return m_tValue < _tValue;
	}


	template <typename T>
	inline bool CAtomic<T>::operator<=(const T _tValue) const
	{
		return m_tValue <= _tValue;
	}


	template <typename T>
	inline bool CAtomic<T>::operator==(const T _tValue) const
	{
		return m_tValue == _tValue;
	}

	template <typename T>
	inline bool CAtomic<T>::operator!=(const T _tValue) const
	{
		return m_tValue != _tValue;
	}

	template <typename T>
	inline bool CAtomic<T>::operator>=(const T _tValue) const
	{
		return m_tValue >= _tValue;
	}


	template <typename T>
	inline bool CAtomic<T>::operator>(const T _tValue) const
	{
		return m_tValue > _tValue;
	}


	template <typename T>
	inline T CAtomic<T>::operator++(int)
	{
		//The function performs an atomic addition of Value to the value pointed to by Addend. 
		//The result is stored in the address specified by Addend. 
		//The function returns the initial value of the variable pointed to by Addend.
		return ::InterlockedExchangeAdd(reinterpret_cast<volatile long *>(&m_tValue),1);
	}

	template <typename T>
	inline T CAtomic<T>::operator--(int)
	{
		//The function performs an atomic addition of Value to the value pointed to by Addend. 
		//The result is stored in the address specified by Addend. 
		//The function returns the initial value of the variable pointed to by Addend.
		return ::InterlockedExchangeAdd(reinterpret_cast<volatile long *>(&m_tValue),-1);
	}

	template <typename T>
	inline T CAtomic<T>::operator++()
	{
		//Increments (increases by one) the value of the specified 32-bit variable as an atomic operation
		return ::InterlockedIncrement(reinterpret_cast<volatile long *>(&m_tValue));
	}

	template <typename T>
	inline T CAtomic<T>::operator--()
	{
		//Decrements (decreases by one) the value of the specified 32-bit variable as an atomic operation.
		return ::InterlockedDecrement(reinterpret_cast<volatile long *>(&m_tValue));
	}

	template <typename T>
	inline void CAtomic<T>::operator=(const T _tValue)
	{
		//The function sets the first variable to Value, and returns its prior value.
		::InterlockedExchange(reinterpret_cast<volatile long *>(&m_tValue),_tValue);
	}

	template <typename T>
	inline T CAtomic<T>::AtomicAdd(const T _tValue)
	{
		//The function performs an atomic addition of Value to the value pointed to by Addend. 
		//The result is stored in the address specified by Addend. 
		//The function returns the initial value of the variable pointed to by Addend.
		return ::InterlockedExchangeAdd(reinterpret_cast<volatile long *>(&m_tValue),_tValue);
	}

	template <typename T>
	inline T CAtomic<T>::AtomicExchange(const T _tValue)
	{
		//The function sets the first variable to Value, and returns its prior value.
		return ::InterlockedExchange(reinterpret_cast<volatile long *>(&m_tValue),_tValue);
	}

	template <typename T>
	inline T CAtomic<T>::AtomicCompareExchange(const T _tSetValue,const T _tComparend)
	{
		//The function compares the Destination value with the Comparand value. 
		//If the Destination value is equal to the Comparand value, the Exchange value is stored 
		//in the address specified by Destination. Otherwise, no operation is performed.
		//The function returns the initial value of the Destination parameter.
		return ::InterlockedCompareExchange(reinterpret_cast<volatile long *>(&m_tValue),_tSetValue,_tComparend);
	}

	template <typename T>
	inline unsigned char CAtomic<T>::AtomicBitTestAndSet(const long _lOffset)
	{
		//Tests the specified bit of the specified LONG value and sets it to 1. The operation is atomic
		return ::InterlockedBitTestAndSet(reinterpret_cast<volatile long *>(&m_tValue),_lOffset);
	}

	template <typename T>
	inline unsigned char CAtomic<T>::AtomicBitTestAndReset(const long _lOffset)
	{
		//Tests the specified bit of the specified LONG value and sets it to 0. The operation is atomic.
		return ::InterlockedBitTestAndReset(reinterpret_cast<volatile long *>(&m_tValue),_lOffset);
	}

	template <typename T>
	inline unsigned char CAtomic<T>::AtomicBitTestAndComplement(const long _lOffset)
	{  
		//Tests the specified bit of the specified LONG value and complements it. The operation is atomic.
		return ::InterlockedBitTestAndComplement(reinterpret_cast<volatile long *>(&m_tValue),_lOffset); 
	}



	template <typename T> 
	class CAtomic<T*>
	{
	private:
		volatile T* m_pValue;
	public:

		CAtomic();
		CAtomic(const T* _pValue);

		/*
		* Get the current value of m_pValue
		*
		*/
		T* GetValue() const;

		/*
		* Get the specified bit of m_pValue
		*
		*@parm in _lOffset   The bit position to be geted.
		*
		*@return  unsigned char: (0 or 1) the value of the specified bit of m_pValue
		*/
		unsigned char GetBit(const long _lOffset) const;

		bool operator<(const T* _pValue) const;

		bool operator<=(const T* _pValue) const;

		bool operator==(const T* _pValue) const;

		bool operator!=(const T* _pValue) const;

		bool operator>=(const T* _pValue) const;

		bool operator>(const T* _pValue) const;

		/*
		* Increments the value of m_pValue as an atomic operation.
		* Then returns the initial(old) value of m_pValue
		*
		*@return  T*: the initial(old) value of m_pValue
		*/
		T* operator ++(int);

		/*
		*  Decrements the value of m_pValue as an atomic operation.
		* Then returns the initial(old) value of m_pValue
		*
		*@return  T*: the initial(old) value of m_pValue
		*/
		T* operator --(int);

		/*
		* Increments the value of m_pValue as an atomic operation.
		* Then returns the resulting value of m_pValue
		*
		*@return  T*: the resulting value of m_pValue
		*/
		T* operator ++();

		/*
		* Decrements the value of m_pValue as an atomic operation.
		* Then returns the resulting value of m_pValue
		*
		*@return  T*: the resulting value of m_pValue
		*/
		T* operator --();

		/*
		* Sets m_pValue to the specified value as an atomic operation.
		*
		*@parm in _pValue   the specified value 
		*
		*@return  void
		*/
		void operator = (const T* _pValue);

		/*
		* Performs an atomic addition to m_pValue.
		* Then returns the initial(old) value of m_tValue
		*
		*@parm in _pValue   the value to be added to  m_pValue
		*
		*@return  T*: the initial(old) value of m_pValue
		*/
		T* AtomicAdd(const T* _tValue);


		/*
		* Sets m_pValue to the specified value as an atomic operation.
		* Then function returns the initial value of m_tValue
		*
		*@parm in _pValue   the specified value 
		*
		*@return  T*: the initial value of m_pValue
		*/
		T* AtomicExchange(const T* _pValue);

		/*
		* The function compares  m_pValue with the _pComparend value. 
		*If m_pValue is equal to the _pComparend value, the Exchange value is stored in 
		*the address specified by m_pValue. Otherwise, no operation is performed
		* Then function returns the initial(old) value of m_pValue
		*
		*@parm in _pSetValue   the value to be exchanged to  m_pValue
		*@parm in _pComparend  The value to compare to m_pValue
		*
		*@return  T: the initial(old) value of m_pValue
		*/
		T* AtomicCompareExchange(const T* _pSetValue,const T* _pComparend);

		/*
		* Tests the specified bit of m_pValue and sets it to 1. The operation is atomic
		* Then function returns the initial(old) value of the specified bit of m_pValue
		*
		*@parm in _lOffset   The bit position to be tested.
		*
		*@return  unsigned char: (0 or 1) the initial(old) value of the specified bit of m_pValue
		*/
		unsigned char AtomicBitTestAndSet(const long _lOffset);

		/*
		* Tests the specified bit of m_pValue and sets it to 0. The operation is atomic
		* Then function returns the initial(old) value of the specified bit of m_pValue
		*
		*@parm in _lOffset   The bit position to be tested.
		*
		*@return  unsigned char: (0 or 1) the initial(old) value of the specified bit of m_pValue
		*/
		unsigned char AtomicBitTestAndReset(const long _lOffset);

		/*
		*Tests the specified bit of m_pValue and complements it. The operation is atomic.
		* Then function returns the initial(old) value of the specified bit of m_pValue
		*
		*@parm in _lOffset   The bit position to be tested.
		*
		*@return  unsigned char: (0 or 1) the initial(old) value of the specified bit of m_pValue
		*/
		unsigned char AtomicBitTestAndComplement(const long _lOffset);
	};

	template <typename T> 
	inline CAtomic<T*>::CAtomic()
	{
		m_pValue = 0;
	}

	template <typename T>
	inline CAtomic<T*>::CAtomic(const T* _pValue)
	{
		m_pValue = _pValue;
	}

	template <typename T>
	inline T* CAtomic<T*>::GetValue() const
	{
		return m_pValue;
	}

	template <typename T>
	unsigned char CAtomic<T*>::GetBit(const long _lOffset) const
	{
		return m_pValue & (1L<<_lOffset) ? 1 : 0;
	}

	template <typename T>
	inline bool CAtomic<T*>::operator<(const T* _pValue) const
	{
		return m_pValue < _pValue;
	}


	template <typename T>
	inline bool CAtomic<T*>::operator<=(const T* _pValue) const
	{
		return m_pValue <= _pValue;
	}


	template <typename T>
	inline bool CAtomic<T*>::operator==(const T* _pValue) const
	{
		return m_pValue == _pValue;
	}

	template <typename T>
	inline bool CAtomic<T*>::operator!=(const T* _pValue) const
	{
		return m_pValue != _pValue;
	}

	template <typename T>
	inline bool CAtomic<T*>::operator>=(const T* _pValue) const
	{
		return m_pValue >= _pValue;
	}


	template <typename T>
	inline bool CAtomic<T*>::operator>(const T* _pValue) const
	{
		return m_pValue > _pValue;
	}


	template <typename T>
	inline T* CAtomic<T*>::operator++(int)
	{
		//The function performs an atomic addition of Value to the value pointed to by Addend. 
		//The result is stored in the address specified by Addend. 
		//The function returns the initial value of the variable pointed to by Addend.
		return ::InterlockedExchangeAdd(reinterpret_cast<volatile long *>(&m_pValue),1);
	}

	template <typename T>
	inline T* CAtomic<T*>::operator--(int)
	{
		//The function performs an atomic addition of Value to the value pointed to by Addend. 
		//The result is stored in the address specified by Addend. 
		//The function returns the initial value of the variable pointed to by Addend.
		return ::InterlockedExchangeAdd(reinterpret_cast<volatile long *>(&m_pValue),-1);
	}

	template <typename T>
	inline T* CAtomic<T*>::operator++()
	{
		//Increments (increases by one) the value of the specified 32-bit variable as an atomic operation
		return ::InterlockedIncrement(reinterpret_cast<volatile long *>(&m_pValue));
	}

	template <typename T>
	inline T* CAtomic<T*>::operator--()
	{
		//Decrements (decreases by one) the value of the specified 32-bit variable as an atomic operation.
		return ::InterlockedDecrement(reinterpret_cast<volatile long *>(&m_pValue));
	}

	template <typename T>
	inline void CAtomic<T*>::operator=(const T* _pValue)
	{
		//The function sets the first variable to Value, and returns its prior value.
		::InterlockedExchange(reinterpret_cast<volatile long *>(&m_pValue),(long)_pValue);
	}

	template <typename T>
	inline T* CAtomic<T*>::AtomicAdd(const T* _pValue)
	{
		//The function performs an atomic addition of Value to the value pointed to by Addend. 
		//The result is stored in the address specified by Addend. 
		//The function returns the initial value of the variable pointed to by Addend.
		return ::InterlockedExchangeAdd(reinterpret_cast<volatile long *>(&m_pValue),(long)_pValue);
	}

	template <typename T>
	inline T* CAtomic<T*>::AtomicExchange(const T* _pValue)
	{
		//The function sets the first variable to Value, and returns its prior value.
		return ::InterlockedExchange(reinterpret_cast<volatile long *>(&m_pValue),(long)_pValue);
	}

	template <typename T>
	inline T* CAtomic<T*>::AtomicCompareExchange(const T* _pSetValue,const T* _pComparend)
	{
		//The function compares the Destination value with the Comparand value. 
		//If the Destination value is equal to the Comparand value, the Exchange value is stored 
		//in the address specified by Destination. Otherwise, no operation is performed.
		//The function returns the initial value of the Destination parameter.
		return ::InterlockedCompareExchange(reinterpret_cast<volatile long *>(&m_pValue),(long)_pSetValue,(long)_pComparend);
	}

	template <typename T>
	inline unsigned char CAtomic<T*>::AtomicBitTestAndSet(const long _lOffset)
	{
		//Tests the specified bit of the specified LONG value and sets it to 1. The operation is atomic
		return ::InterlockedBitTestAndSet(reinterpret_cast<volatile long *>(&m_pValue),_lOffset);
	}

	template <typename T>
	inline unsigned char CAtomic<T*>::AtomicBitTestAndReset(const long _lOffset)
	{
		//Tests the specified bit of the specified LONG value and sets it to 0. The operation is atomic.
		return ::InterlockedBitTestAndReset(reinterpret_cast<volatile long *>(&m_pValue),_lOffset);
	}

	template <typename T>
	inline unsigned char CAtomic<T*>::AtomicBitTestAndComplement(const long _lOffset)
	{  
		//Tests the specified bit of the specified LONG value and complements it. The operation is atomic.
		return ::InterlockedBitTestAndComplement(reinterpret_cast<volatile long *>(&m_pValue),_lOffset); 
	}


}